#!/usr/bin/python
# author dennis
# 2022年07月20日
import numpy
import pandas as pd
from numpy import *


def gen_dataset():
    from sklearn.datasets import make_blobs
    import matplotlib.pyplot as plt
    random.seed(13)
    data, label = make_blobs(centers=4, n_samples=100)
    dataMat = data
    labelMat = label
    # data = array(data)
    # data2 = array(label)
    # print(data)
    # print(data2)
    # 绘制数据分布
    # plt.figure(figsize=(6, 4))
    # plt.scatter(X[:, 0], X[:, 1], c=y)
    # plt.title("Dataset")
    # plt.show()
    # for i in range(data.shape[0]):
    #     dataMat.append([1.0, numpy.float(data[0]), numpy.float(data[1])])
    return dataMat, labelMat


def softmax(z):
    m, k = z.shape
    p = zeros([m, k])
    # c = max(z.all())
    for i in range(m):
        p[i, :] = exp((z[i, :])) / sum(exp(z[i, :]))
    return p


def celoss(theta, x, y):  # x(m行n列），y（m行k列），theta（k行n列）
    [k, m] = y.shape
    theta = matrix(theta)
    sum = 0
    p = softmax(dot(x, theta))  ## [m,k]
    p = p.T.reshape([k * m, 1])
    y = y.reshape([k * m, 1])
    temp_p = mat(log(p))
    cost = -1 / m * dot(y.T, temp_p)
    return cost  # 输出m行k列，代表m个样本，k个类别各自概率


def gradAscent(dataMat, labelMat):  # 梯度上升求最优参数
    dataMatrix = mat(dataMat)  # 将读取的数据转换为矩阵
    classLabels = mat(labelMat).transpose()  # 将读取的数据转换为矩阵
    m, n = shape(dataMatrix)
    alpha = 0.001  # 设置梯度的阀值，该值越大梯度上升幅度越大
    maxCycles = 500  # 设置迭代的次数，一般看实际数据进行设定，有些可能200次就够了
    weights = ones((n, 1))  # 设置初始的参数，并都赋默认值为1。注意这里权重以矩阵形式表示三个参数。
    for k in range(maxCycles):
        weights = weights + alpha * mat(celoss(weights,dataMatrix,classLabels))
    return weights


# 显示数据
def plotBestFit(weights, dataMat, labelMat):  # 画出最终分类的图
    import matplotlib.pyplot as plt
    fig = plt.figure(figsize=(6, 4))
    ax = fig.add_subplot(111)
    plt.scatter(dataMat[:, 0], dataMat[:, 1], c=labelMat)
    plt.title("Dataset")
    x = arange(-10, 10, 0.1)
    y = (- weights[0,0]-weights[0,1] * x) / weights[0,2]
    ax.plot(x, y)
    # elif labelMat[i] == 2:
    #     y = (-weights[0] - weights[1] * x) / weights[2]
    #     ax.plot(x, y)
    # elif labelMat[i] == 3:
    #     y = (-weights[0] - weights[1] * x) / weights[2]
    #     ax.plot(x, y)
    # elif labelMat[i] == 4:
    #     y = (-weights[0] - weights[1] * x) / weights[2]
    #     ax.plot(x, y)
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.show()


def main():
    dataMat, labelMat = gen_dataset()
    weights = gradAscent(dataMat, labelMat)
    print(weights)
    plotBestFit(weights, dataMat, labelMat)


if __name__ == '__main__':
    seterr(divide='ignore', invalid='ignore')
    main()
